#include "player.h"
#include <QDebug>
#include <QTime>
#include "math.h"

Player::Player(qreal x, qreal y) : MovingObject()
{
    speed = 3.0;
    changePos(QPointF(x,y));
    radius = 9;
    wsp_m = 180.0 / 3.14159265;;
    usesMouse = false;
    dirs.clear();
	dirs.append(0);
	dirs.append(0);
	deathTime = 0;
    setZValue(3);
}

Player::~Player()
{
	delete gun;
}

void Player::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                QWidget *widget) {
    Q_UNUSED(option);
    Q_UNUSED(widget);
    aimAtMouse();
    qreal r = radius;
    painter->drawEllipse(-r,-r,r*2,r*2);
    QLineF line(0,0,radius,0);
    line.setAngle(angle);
    r = r - 1;

    QPen pen;
    QBrush brush;
    //brush.setColor(Qt::red);
    brush.setColor(QColor(255,150,150));
    brush.setStyle(Qt::SolidPattern);
    pen.setColor(QColor(255,150,150));
    painter->setPen(pen);
    painter->setBrush(brush);
    QRectF rectangle(-r, -r, 2*r, 2*r);
    QPainterPath piePath;

    double arc = 0;
    int item = 0;
    if (gun != NULL) {
        int status = gun->getStatus();
        if (status == 0)
        {
            item = gun->getClip();
            if (item != 0)
            {
                arc = 360.0 * (double(item) / double(gun->getClipSize()) );
            }
        } else {
            item = gun->getReload();
            if (item != 0)
            {
                arc = 360.0 * (double(item) / double(gun->getReloadTime() ));
            }
        }

    }

    if (item > 0)
    {
        piePath.moveTo(0, 0);
        piePath.arcTo(-r, -r, 2*r, 2*r, 0.0, arc);
        piePath.closeSubpath();
        painter->drawPath(piePath);

    }
    pen.setColor(Qt::black);
    painter->setPen(pen);
    painter->drawLine(line);
}

QRectF Player::boundingRect() const
{
    return QRect(-radius,-radius,radius*2,radius*2);
}

QPainterPath Player::shape() const
{
    QPainterPath path;
    path.addEllipse(boundingRect());
    return path;
}

ConnectionPlayer* Player::getConnectionPlayer()
{
	return connectionPlayer;
}

ClientConnection* Player::getClientConnection()
{
	return clientConnection;
}

void Player::setConnectionPlayer(ConnectionPlayer* cp)
{
	connectionPlayer = cp;

	connect(connectionPlayer, SIGNAL(positionChanged(QPointF)), this, SLOT(setPosition(QPointF)));
	connect(connectionPlayer, SIGNAL(isAliveChanged(bool)), this, SLOT(setIsAlive(bool)));
	connect(connectionPlayer, SIGNAL(isReloadingChanged(bool)), this, SLOT(setIsReloading(bool)));
	connect(connectionPlayer, SIGNAL(angleChanged(qint16)), this, SLOT(setAngle(qint16)));
	connect(connectionPlayer, SIGNAL(dirsChanged(quint8, quint8)), this, SLOT(setDirs(quint8, quint8)));
	connect(connectionPlayer, SIGNAL(gunFired(qreal,qreal,qreal)), this, SLOT(fireGun(qreal,qreal,qreal)));
}

void Player::setClientConnection(ClientConnection* cc)
{
	clientConnection = cc;
	connect(clientConnection, SIGNAL(isAliveChanged(bool)), this, SLOT(setIsAlive(bool)));
}

bool Player::movePlayer()
{
    gun->updateGun();
    qreal speed_fix = speed;
    int dir[2] = {0,0};
    bool wasOdd = false;
    int count = 0;

    for (int i = 0; (i < dirs.size()) && count < 2; ++i)
    {
        if (count == 0) {
            dir[count] = dirs[i];
            wasOdd = (dir[count] % 2) == 1;
            count++;
        } else {
            if ((dirs[i] % 2) != wasOdd) {
                dir[count] = dirs[i];
                count++;
            } else {

                continue;
            }
        }
    }
    if (!isRemote) {
    	clientConnection->setIsAlive(isAlive);
    	clientConnection->setPosition(pos());
    	clientConnection->dirs.clear();
    	clientConnection->dirs.append(dir[0]);
    	clientConnection->dirs.append(dir[1]);
    	clientConnection->setAngle(angle);
    	clientConnection->setIsReloading(gun->getStatus() == 1);
	}
    if (count == 2) speed_fix = (speed*sqrt(2))/2;
    double dx = 0.0;
    double dy = 0.0;
    for (int i = 0; i < count; i++)
    {
        switch (dir[i]) {
            case 1://W
                    dy -= speed_fix;
                    break;
            case 2://D
                    dx += speed_fix;
                    break;
            case 3://S
                    dy += speed_fix;
                    break;
            case 4://A
                    dx -= speed_fix;
                    break;
            default:
                    break;
        }
    }

    return movePlayerBy(dx,dy);

}

bool Player::movePlayerBy(qreal dx, qreal dy)
{
    if ((dx != 0 || dy != 0))
    {
        moveBy(dx,dy);
        realPos = pos();
        return true;
    } else {
        return false;
    }
}

bool Player::movePlayerBy(QLineF vector)
{
    return movePlayerBy(vector.dx(), vector.dy());
}

void Player::setPlayerAngle(qreal ang)
{
    angle = ang;
    gun->setGunAngle(ang);
}

void Player::changeXPos(qreal x)
{
    changePos(x, this->y());
}

void Player::changeYPos(qreal y)
{
    changePos(this->x(), y);

}

void Player::changePos(QPointF p)
{
    setPos(p);
    realPos = p;
}

void Player::changePos(qreal x, qreal y)
{
    changePos(QPointF(x,y));
}

qreal Player::getRadius()
{
    return radius+1;
}

void Player::updateKeys(int nr) {
    dirs.push_front(nr);
}

void Player::aimAtMouse()
{
    if (usesMouse)
    {
        double xd = mouse->x() - realPos.rx();
        double yd = mouse->y() - realPos.ry() ;

        double add = 0.0;
        if (xd < 0) add = 180.0;
        double angle = wsp_m*atan(yd/xd) + add;

        setPlayerAngle(-angle);
    }
}

int Player::keyToNr(int key) {

        if (key==Qt::Key_A) {
                return 4;
        } else if (key==Qt::Key_W) {
                return 1;
        } else if (key==Qt::Key_D) {
                return 2;
        } else if (key==Qt::Key_S) {
                return 3;
        } else {
                return 0;
        }
}

void Player::keyPressEvent(QKeyEvent* evt) {
        if (!evt->isAutoRepeat()) {
                int nr = keyToNr(evt->key());
                if (nr != 0) {
                        updateKeys(nr);
                }
        }
}

void Player::keyReleaseEvent(QKeyEvent* evt) {
        if (!evt->isAutoRepeat()) {

                int nr = keyToNr(evt->key());
                if (nr != 0) {
                        dirs.removeOne(nr);
                }
        }
}

void Player::setMouse(Mouse* m)
{
    mouse = m;
    usesMouse = true;
    connect(mouse, SIGNAL(mousePressed(QMouseEvent*)), this, SLOT(onMousePressed(QMouseEvent*)));
    connect(mouse, SIGNAL(mouseReleased(QMouseEvent*)), this, SLOT(onMouseReleased(QMouseEvent*)));
}

void Player::setGun(Gun* g)
{
    gun = g;
    gun->setOwner(this);
    gun->fireReleased();
    connect(gun, SIGNAL(gunFired(Bullet*)), this, SLOT(onGunFired(Bullet*)));
    connect(gun, SIGNAL(hitPlayer(Player*,Player*)), this, SLOT(onHitPlayer(Player*,Player*)));
}

void Player::setIsAlive(bool ia)
{
	//qDebug() << "making player alive" << ia;
	setVisible(ia);
	isAlive = ia;
	if (ia) {
		qDebug() << "I am alive" << isVisible();
		gun->fireReleased();
		health = 100;
	}
	if (ia && !isRemote) {
		grabKeyboard();
		setPosition(clientConnection->getPos());
	}

}

void Player::setPosition(QPointF p)
{
	changePos(p);
}

void Player::setIsReloading(bool isr)
{
	if (isr && (gun->getStatus() == 0))
	{
		gun->startReloading();
	}
	else
	{
		gun->finishReloading();
	}
}

void Player::setAngle(qint16 a)
{
	angle = a;
}

void Player::setDirs(quint8 d1, quint8 d2)
{
	dirs.clear();
	dirs.append(d1);
	dirs.append(d2);
}

void Player::setIsRemote(bool isr)
{
	isRemote = isr;
}

void Player::decreaseHealth(qreal h)
{
	health -= h;
	if (health <= 0)
	{
		health = 0;
		if (getIsRemote())
		{
			deathTime = time(0);
			connectionPlayer->setIsAlive(false);
		}
	}
}

void Player::unsetMouse()
{
    mouse = NULL;
    usesMouse = false;
}

QVector<Bullet*> Player::getBullets()
{
    return gun->getBullets();
}

quint32 Player::getDeathTime()
{
	return deathTime;
}

void Player::setDeathTime(quint32 dt)
{
	deathTime = dt;
}

void Player::onMousePressed(QMouseEvent *evt)
{
	if (isAlive) {
		gun->firePressed();
	}
}

void Player::onMouseReleased(QMouseEvent *evt)
{
	if (isAlive) {
		gun->fireReleased();
	}
}

void Player::onHitPlayer(Player* p1, Player* p2)
{
	qDebug() << "player emit hit";
	emit hitPlayer(p1,p2);
}

void Player::onGunFired(Bullet* b)
{
    if (b != NULL)
    {


        map()->addItem(b);
        if (!isRemote) {
        	clientConnection->sendShootMsg(pos().rx(), pos().ry(), qRound(angle));
        }
    }
}


void Player::fireGun(qreal x, qreal y, qreal angle)
{
	if (isAlive) {
		if (getIsRemote()) {
			qDebug() << "reset gun";
			gun->resetGun();
		}
		gun->fire(x,y,angle);
	}
}

Map *Player::map()
{
    return static_cast<Map *>(scene());
}



